#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>

#define PORT 8080
#define CGI_BIN_PATH "./cgi-bin/"
#define DOCUMENT_ROOT "./static/"
#define MAX_REQUEST_SIZE 8192
#define MAX_RESPONSE_SIZE 65536

// 环境变量结构
typedef struct
{
    char *name;
    char *value;
} EnvVar;

// 设置CGI环境变量
EnvVar *setup_cgi_env(int client_sock, char *method, char *path, char *query, char *content, size_t content_len)
{
    static EnvVar env[22];

    // 客户端地址
    struct sockaddr_in client_addr;
    socklen_t len = sizeof(client_addr);
    getpeername(client_sock, (struct sockaddr *)&client_addr, &len);
    char client_ip[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);

    // 填充环境变量
    env[0] = (EnvVar){"CONTENT_LENGTH", content ? (char *)malloc(20) : "0"};
    if (content)
        sprintf(env[0].value, "%zu", content_len);

    env[1] = (EnvVar){"CONTENT_TYPE", "application/x-www-form-urlencoded"};
    env[2] = (EnvVar){"GATEWAY_INTERFACE", "CGI/1.1"};
    env[3] = (EnvVar){"PATH_INFO", path};
    env[4] = (EnvVar){"QUERY_STRING", query ? query : ""};
    env[5] = (EnvVar){"REMOTE_ADDR", client_ip};
    env[6] = (EnvVar){"REQUEST_METHOD", method};
    env[7] = (EnvVar){"REQUEST_URI", path};
    env[8] = (EnvVar){"SCRIPT_NAME", path};
    env[9] = (EnvVar){"SERVER_PORT", "8080"};
    env[10] = (EnvVar){"SERVER_PROTOCOL", "HTTP/1.1"};
    env[11] = (EnvVar){"SERVER_SOFTWARE", "Liso/1.0"};

    // 以下变量在实际应用中应从请求头中解析
    env[12] = (EnvVar){"HTTP_ACCEPT", "*/*"};
    env[13] = (EnvVar){"HTTP_REFERER", "http://localhost:8080/form.html"};
    env[14] = (EnvVar){"HTTP_ACCEPT_ENCODING", "gzip, deflate"};
    env[15] = (EnvVar){"HTTP_ACCEPT_LANGUAGE", "en-US,en;q=0.9"};
    env[16] = (EnvVar){"HTTP_ACCEPT_CHARSET", "utf-8"};
    env[17] = (EnvVar){"HTTP_HOST", "localhost:8080"};
    env[18] = (EnvVar){"HTTP_COOKIE", "session=abc123"};
    env[19] = (EnvVar){"HTTP_USER_AGENT", "Mozilla/5.0"};
    env[20] = (EnvVar){"HTTP_CONNECTION", "keep-alive"};
    env[21] = (EnvVar){NULL, NULL}; // 结束标记

    return env;
}

// 执行CGI程序
int execute_cgi(int client_sock, char *cgi_path, EnvVar *env, char *content)
{
    int pipe_in[2], pipe_out[2];
    pid_t pid;
    char buf[1024];
    ssize_t n;

    // 创建管道
    if (pipe(pipe_in))
        return -1;
    if (pipe(pipe_out))
    {
        close(pipe_in[0]);
        close(pipe_in[1]);
        return -1;
    }

    // 创建子进程
    if ((pid = fork()) < 0)
    {
        close(pipe_in[0]);
        close(pipe_in[1]);
        close(pipe_out[0]);
        close(pipe_out[1]);
        return -1;
    }

    if (pid == 0)
    { // 子进程 - CGI程序
        // 关闭不必要的管道端
        close(pipe_in[1]);
        close(pipe_out[0]);

        // 重定向标准输入输出
        dup2(pipe_in[0], STDIN_FILENO);
        dup2(pipe_out[1], STDOUT_FILENO);

        // 关闭原始管道
        close(pipe_in[0]);
        close(pipe_out[1]);

        // 设置环境变量
        int env_count = 0;
        while (env[env_count].name != NULL)
        {
            setenv(env[env_count].name, env[env_count].value, 1);
            env_count++;
        }

        // 执行CGI程序
        execl(cgi_path, cgi_path, NULL);

        // 如果执行失败
        perror("execl failed");
        exit(EXIT_FAILURE);
    }
    else
    { // 父进程 - 服务器
        // 关闭不必要的管道端
        close(pipe_in[0]);
        close(pipe_out[1]);

        // 写入请求内容（如果有）
        if (content)
        {
            write(pipe_in[1], content, strlen(content));
        }
        close(pipe_in[1]);

        // 读取CGI输出
        char response[MAX_RESPONSE_SIZE] = {0};
        ssize_t total = 0;
        while ((n = read(pipe_out[0], buf, sizeof(buf))))
        {
            if (n < 0)
                break;
            if (total + n < MAX_RESPONSE_SIZE)
            {
                memcpy(response + total, buf, n);
                total += n;
            }
        }
        close(pipe_out[0]);

        // 等待子进程结束
        int status;
        waitpid(pid, &status, 0);

        // 检查CGI执行状态
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
        {
            // 成功 - 发送响应
            dprintf(client_sock, "HTTP/1.1 200 OK\r\n");
            dprintf(client_sock, "Content-Length: %zd\r\n", total);
            dprintf(client_sock, "Content-Type: text/html\r\n\r\n");
            write(client_sock, response, total);
        }
        else
        {
            // 失败 - 返回500错误
            dprintf(client_sock, "HTTP/1.1 500 Internal Server Error\r\n");
            dprintf(client_sock, "Content-Type: text/html\r\n\r\n");
            dprintf(client_sock, "<html><body><h1>500 Internal Server Error</h1>");
            dprintf(client_sock, "<p>CGI execution failed</p></body></html>");
        }

        return 0;
    }
}

// 主服务器循环
int main()
{
    int server_fd, client_sock;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    // 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 配置套接字
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // 绑定套接字
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听
    if (listen(server_fd, 10) < 0)
    {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }

    printf("Server running on port %d\n", PORT);

    while (1)
    {
        // 接受连接
        printf("Waiting for connections...\n");
        if ((client_sock = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0)
        {
            perror("accept failed");
            continue;
        }
        printf("Accepted connection from %s:%d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
        char request[MAX_REQUEST_SIZE] = {0};
        read(client_sock, request, sizeof(request));

        // 解析请求行
        char method[16], path[256], protocol[16];
        sscanf(request, "%s %s %s", method, path, protocol);

        // 解析查询字符串
        char *query = strchr(path, '?');
        if (query)
        {
            *query = '\0';
            query++;
        }

        // 解析内容长度
        char *content = NULL;
        size_t content_len = 0;
        if (strstr(request, "Content-Length:"))
        {
            char *cl = strstr(request, "Content-Length:") + 15;
            content_len = atoi(cl);

            content = strstr(request, "\r\n\r\n");
            if (content)
            {
                content += 4;
                if (strlen(content) > content_len)
                {
                    content[content_len] = '\0';
                }
            }
        }

        // 检查CGI请求
        if (strncmp(path, "/cgi-bin/", 9) == 0)
        {
            char cgi_path[256];
            snprintf(cgi_path, sizeof(cgi_path), "%s%s", CGI_BIN_PATH, path + 9);

            // 设置环境变量
            EnvVar *env = setup_cgi_env(client_sock, method, path, query, content, content_len);

            // 执行CGI程序
            if (execute_cgi(client_sock, cgi_path, env, content) < 0)
            {
                // CGI执行失败
                dprintf(client_sock, "HTTP/1.1 500 Internal Server Error\r\n");
                dprintf(client_sock, "Content-Type: text/html\r\n\r\n");
                dprintf(client_sock, "<html><body><h1>500 Internal Server Error</h1>");
                dprintf(client_sock, "<p>Failed to execute CGI script</p></body></html>");
            }

            // 清理环境变量
            for (int i = 0; env[i].name != NULL; i++)
            {
                if (env[i].name == "CONTENT_LENGTH" && content)
                {
                    free(env[i].value);
                }
            }
        }
        else
        {
            // 处理静态文件
            char file_path[256];
            snprintf(file_path, sizeof(file_path), "%s%s", DOCUMENT_ROOT,
                     strcmp(path, "/") == 0 ? "/form.html" : path);

            FILE *file = fopen(file_path, "r");
            if (file)
            {
                fseek(file, 0, SEEK_END);
                long size = ftell(file);
                fseek(file, 0, SEEK_SET);

                char *content = malloc(size + 1);
                fread(content, 1, size, file);
                fclose(file);

                dprintf(client_sock, "HTTP/1.1 200 OK\r\n");
                dprintf(client_sock, "Content-Length: %ld\r\n", size);

                if (strstr(file_path, ".html"))
                {
                    dprintf(client_sock, "Content-Type: text/html\r\n\r\n");
                }
                else if (strstr(file_path, ".css"))
                {
                    dprintf(client_sock, "Content-Type: text/css\r\n\r\n");
                }
                else
                {
                    dprintf(client_sock, "Content-Type: text/plain\r\n\r\n");
                }

                write(client_sock, content, size);
                free(content);
            }
            else
            {
                // 文件未找到
                dprintf(client_sock, "HTTP/1.1 404 Not Found\r\n");
                dprintf(client_sock, "Content-Type: text/html\r\n\r\n");
                dprintf(client_sock, "<html><body><h1>404 Not Found</h1></body></html>");
            }
        }

        close(client_sock);
    }

    return 0;
}